package systeme;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import rdp.*;

public class AlgoGrapheRdP {

	RdP rdp;

	public AlgoGrapheRdP(RdP rdp) {

		this.rdp = rdp;
	}

	

	public boolean franchissable(boolean[] m, int t) {

		for (int i = 0; i < rdp.pre[t].length; ++i) {

			if (!m[rdp.pre[t][i]])

				return false;
		}

		return true;
	}

	public boolean[] franchir(boolean[] m, int t) throws Exception {

		boolean[] res = new boolean[rdp.place.length];

		res = Arrays.copyOf(m, rdp.place.length);

		for (int i = 0; i < rdp.pre[t].length; i++)

			if (m[rdp.pre[t][i]])
				res[rdp.pre[t][i]] = false;

		for (int i = 0; i < rdp.post[t].length; i++)

			if (!res[rdp.post[t][i]])
				res[rdp.post[t][i]] = true;
			else
				// Pourquoi le réseau n'est pas sain
				// On connait le marquage m et la place qui est post[t][i]
				throw new Exception ("Mauvais franchissement " + rdp.toStringMarquage(m) + " transition " + rdp.transition[t] + " place " + rdp.place[rdp.post[t][i]]);
		return res;
	}

	public GrapheRdP grapheRdP() throws Exception {

		GrapheRdP res = new GrapheRdP();

		res.rdp = rdp;

		res.etat = new ArrayList<boolean[]>();
		res.succ = new ArrayList<ArrayList<Integer>>();
		res.pred = new ArrayList<ArrayList<Integer>>();
		
		HashMap<Etat, Integer> table = new HashMap<Etat, Integer>();

		recGrapheRdp(rdp.marquage, res, table);
		
		// On remplie les pred 
		remplirPred(res);
		
		return res;
	}

	public void remplirPred(GrapheRdP res){
		
		int taille = res.succ.size() ;
		ArrayList<Integer> lesSuccs ;
		int nbSucc ;
		
		// Pour tous les états
		for (int i = 0 ; i < taille ; i ++){
			
			lesSuccs = res.succ.get(i);
			nbSucc = lesSuccs.size();
			
			// On récupère les successeurs
			for(int j = 0 ; j < nbSucc ; j++){
				// Si je suis le succ de quelqu'un 
				// Alors il est mon pred
				res.pred.get(lesSuccs.get(j)).add(i);
				
			}
			
			
		}
	}
	public void recGrapheRdp(boolean[] m, GrapheRdP res, Map<Etat, Integer> table) throws Exception{
		
		table.put(new Etat(m), res.etat.size());
		res.nbEtat++;
		res.etat.add(m);

		ArrayList<Integer> succM = new ArrayList<Integer>();
		res.succ.add(succM);
		res.pred.add(new ArrayList<Integer>());
		
		for (int t = 0; t < rdp.pre.length; ++t) {

			if (franchissable(m, t)) {

				res.nbTransition++;

				boolean[] mp = franchir(m, t);

				Integer index = table.get(new Etat(mp));

				if (index == null) {

					succM.add(res.etat.size());

					recGrapheRdp(mp, res, table);

				} else

					succM.add(index);
			}
		}
	}


	static class Etat {

		boolean[] val;

		// constructeur obtenu par exlipse;
		public Etat(boolean[] val) {

			this.val = val;

		}

		// hashcode, equal eclipse
		public boolean equals(Etat e) {

			return val.equals(e);
		}
	}
}